package com.starblink.web.util

import android.content.Context
import android.os.Looper
import android.webkit.MimeTypeMap
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import com.bumptech.glide.Glide
import com.starblink.android.basic.bridge.*
import com.starblink.android.basic.sensorsdata.spm.GTrackerAssistUtils
import com.starblink.basic.log.SKLogger
import com.starblink.http.cache.IntelligentCache
import com.starblink.web.core.GuangWebView
import com.starblink.web.okhttp.CallBackUtil
import com.starblink.web.okhttp.OkhttpUtil
import kotlinx.coroutines.runBlocking
import okhttp3.Call
import okio.ByteString.Companion.encodeUtf8
import java.io.File

object WebCacheUtil : PreLoadUrlBridgeI{
    private const val TAG="GuangWebView"
    private var webViewCache= IntelligentCache<GuangWebView>(2) //已经缓存链接
    private var urlCacheIngList=ArrayList<String>() //待缓存链接
    private var ifQueueIdle:Boolean=false //true会一直执行 false只执行一遍

    fun init() {
        //跨进程web预加载使用
        CommonBridge.preLoadUrlBridgeI=this
    }

    //跨进程预加载H5
    fun preLoadUrl(cacheUrl: String){
        BridgeUtil.sendCommonData(BridgeCommand.Common.preLoadUrl, cacheUrl,true)
    }

    //缓存单个url
    override fun preLoadUrl(context: Context, cacheUrl: String){
        var urlList=ArrayList<String>()
        urlList.add(cacheUrl)
        preLoadUrl(context,urlList)
    }
    //批量缓存单个url
    fun preLoadUrl(context: Context, urlList: List<String>){
        for (cacheUrl in urlList) {
            if(webViewCache.containsKey(cacheUrl)){
                //已缓存
                SKLogger.d(TAG,"已缓存 $cacheUrl")
                continue
            }
            if(urlCacheIngList.indexOf(cacheUrl)!=-1){
                //已在待缓存列表
                SKLogger.d(TAG,"已在待缓存列表 $cacheUrl")
                continue
            }
            //加入待缓存列表
            urlCacheIngList.add(cacheUrl)
        }

        startPreLoadUrl(context)
    }
    //清理已缓存webview
    fun clearPreWebView(){
        val it: MutableIterator<Map.Entry<String, GuangWebView>> = webViewCache.cacheMap.entries.iterator()
        while (it.hasNext()) {
            val item = it.next()
            SKLogger.d(TAG,"clearPreWebView ${item.key}")
            item.value.onDestroy()
            it.remove()
        }
    }
    //获取已缓存webview
    fun getPreWebView(loadUrl:String): GuangWebView?{
        var cacheWebView=webViewCache.get(loadUrl)
        cacheWebView?.let {
            webViewCache.remove(loadUrl)
        }
        return cacheWebView
    }

    //开始预加载url
    private fun startPreLoadUrl(context: Context){
        if(ifQueueIdle){
            return
        }
        Looper.myQueue().addIdleHandler {
            if(urlCacheIngList.size>0){
                var cacheUrl= urlCacheIngList[0]
                SKLogger.d(TAG,"缓存ing地址 $cacheUrl")
                var webView=GuangWebViewPool.getInstance().getPreWebView(context)
                webView.guangLoadUrl(url=cacheUrl)
                urlCacheIngList.remove(cacheUrl)
                webViewCache.put(cacheUrl,webView)
            }
            ifQueueIdle= urlCacheIngList.size>0
            ifQueueIdle
        }
    }

    //资源拦截加载
    fun shouldInterceptRequest(view: WebView,
                               request: WebResourceRequest): WebResourceResponse? {
//        SKLogger.d(TAG, "拦截资源HEADER：${request.requestHeaders}")

        var webResourceResponse: WebResourceResponse? = null
        // 如果是 assets 目录下的文件 暂时没有本地资源
//            if (isAssetsResource(request)) {
//                webResourceResponse = assetsResourceRequest(view.context, request)
//            }

        // 如果是可以缓存的文件
        if (isCacheResource(request)) {
            webResourceResponse = cacheResourceRequest(view.context, request)
        }
        if(webResourceResponse!=null){
            SKLogger.d(TAG,"SUCCESS--命中缓存 ${request.url}")
        }else{
            SKLogger.d(TAG,"FAIL--没有命中缓存 ${request.url}")
        }
        return webResourceResponse
    }

    //是否本地资源文件
    private fun isAssetsResource(webRequest: WebResourceRequest?): Boolean {
        val url = webRequest?.url.toString()
        return url.startsWith("file:///android_asset/")
    }

    /**
     * assets 文件请求
     */
    private fun assetsResourceRequest(
        context: Context,
        webRequest: WebResourceRequest
    ): WebResourceResponse? {
        val url = webRequest.url.toString()
        try {
            val filenameIndex = url.lastIndexOf("/") + 1
            val filename = url.substring(filenameIndex)
            val suffixIndex = url.lastIndexOf(".")
            val suffix = url.substring(suffixIndex + 1)
            val webResourceResponse = WebResourceResponse(
                getMimeTypeFromUrl(url),
                "UTF-8",
                context.assets.open("$suffix/$filename")
            )
            webResourceResponse.responseHeaders = mapOf("access-control-allow-origin" to "*")
            return webResourceResponse
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * 根据 url 获取文件类型
     */
    private fun getMimeTypeFromUrl(url: String): String {
        try {
            val extension = MimeTypeMap.getFileExtensionFromUrl(url)
            if (extension.isNotBlank() && extension != "null") {
                if (extension == "json") {
                    return "application/json"
                }
                return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) ?: "*/*"
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return "*/*"
    }

    /**
     * 判断是否是可以被缓存等资源
     */
    private fun isCacheResource(webRequest: WebResourceRequest): Boolean {
        //根据资源后缀类型缓存 缓存html文件会影响是否真人判断检测 人机检测页面会空白
        val url = webRequest.url.toString()
        val extension = MimeTypeMap.getFileExtensionFromUrl(url)
        SKLogger.d(TAG,"资源类型--$extension---$url")
        return extension == "ico" || extension == "bmp" || extension == "gif"
                || extension == "jpeg" || extension == "jpg" || extension == "png"
                || extension == "svg" || extension == "webp" || extension == "css"
                || extension == "js" || extension == "json" || extension == "eot"
                || extension == "otf" || extension == "ttf" || extension == "woff"
                || extension == "woff2"
    }

    /**
     * 可缓存文件请求
     */
    private fun cacheResourceRequest(
        context: Context,
        webRequest: WebResourceRequest
    ): WebResourceResponse? {
        val url = webRequest.url.toString()
        val mimeType = getMimeTypeFromUrl(url)

        // WebView 中的图片利用 Glide 加载(能够和App其他页面共用缓存) 发现走glide比直接取本地慢
//        if (isImageResource(webRequest)) {
//            return try {
//                val file = Glide.with(context).download(url).submit().get()
//                val webResourceResponse = WebResourceResponse(mimeType, "UTF-8", file.inputStream())
//                webResourceResponse.responseHeaders = mapOf("access-control-allow-origin" to "*")
//                webResourceResponse
//            } catch (e: Exception) {
//                e.printStackTrace()
//                null
//            }
//        }

        /**
         * 其他文件缓存逻辑
         * 1.寻找缓存文件，本地有缓存直接返回缓存文件
         * 2.无缓存，下载到本地后返回
         * 注意！！！
         * 一定要确保文件下载完整，我这里采用下载完成后给文件加 "success-" 前缀的方法
         */
        val webCachePath = getWebViewCachePath(context)
        val destFileName=url.encodeUtf8().md5().hex()
        val cacheFilePath =
            webCachePath + File.separator + "success-" + destFileName // 自定义文件命名规则
        val cacheFile = File(cacheFilePath)
        if (!cacheFile.exists() || !cacheFile.isFile) { // 本地不存在 则开始下载
            // 下载文件

            val sourceFilePath = webCachePath + File.separator + destFileName
            val sourceFile = File(sourceFilePath)

            //资源文件下载
            runBlocking {
                try {
                    OkhttpUtil.okHttpDownloadFile(url,null,webRequest.requestHeaders,object :
                        CallBackUtil.CallBackFile(webCachePath,destFileName) {
                        override fun onFailure(call: Call?, e: java.lang.Exception?) {
                            SKLogger.d(TAG,"FAIL--Download缓存失败 $url")
                        }

                        override fun onResponse(call: Call?, response: File?) {
                            SKLogger.d(TAG,"SUCCESS--Download缓存成功 $url")
                            // 下载完成后增加 "success-" 前缀 代表文件无损 【防止io流被异常中断导致文件损坏 无法判断】
                            response?.renameTo(cacheFile)
                        }
                    })
                } catch (e: Exception) {
                    e.printStackTrace()
                    // 发生异常删除文件
                    sourceFile.deleteOnExit()
                    cacheFile.deleteOnExit()
                }
            }
        }

        // 缓存文件存在则返回
        if (cacheFile.exists() && cacheFile.isFile) {
            val webResourceResponse =
                WebResourceResponse(mimeType, "UTF-8", cacheFile.inputStream())
            webResourceResponse.responseHeaders = mapOf("access-control-allow-origin" to "*")
            return webResourceResponse
        }
        return null
    }

    /**
     * 判断是否是图片
     * 有些文件存储没有后缀，也可以根据自家服务器域名等等
     */
    private fun isImageResource(webRequest: WebResourceRequest): Boolean {
        val url = webRequest.url.toString()
        val extension = MimeTypeMap.getFileExtensionFromUrl(url)
        return extension == "ico" || extension == "bmp" || extension == "gif"
                || extension == "jpeg" || extension == "jpg" || extension == "png"
                || extension == "svg" || extension == "webp"
    }

    /**
     * 获取 WebView 缓存文件目录
     */
    fun getWebViewCachePath(context: Context): String{
        return context.filesDir.absolutePath + "/webCache"
    }

    /**
     * 删除本地H5缓存文件夹
     */
    fun clearCacheFolder(cacheFolder: File){
        try {
            if (cacheFolder.isDirectory) {
                cacheFolder.listFiles()?.let {
                    for (child in it) {
                        if (child.isDirectory) {
                            clearCacheFolder(child)
                        }
                        child.delete()
                    }
                }
            }
        }catch (e:Exception){
            e.printStackTrace()
        }
    }
}